﻿namespace OutLook.Module.Load
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using OutLook.Module.Infrastructure;
    using OutLook.Module.Load.Contracts;
    using OutLook.Module.Infrastructure.Interfaces;
    using OutLook.Model.Domains;
    using System.Data;
    using OutLook.Module.Load.Properties;
    using OutLook.Model.Infrastructure;
    using OutLook.Properties.Calc;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class OutputController : DomainControllerBase, IOutputContract
    {
        #region Constructors

        public OutputController(IRepository context)
            : base(context) { }

        #endregion

        #region Properties

        public Output CurrentOutput
        {
            get { return m_CurrentOutput; }
            set { m_CurrentOutput = value; }
        }

        #endregion

        #region DomainControllerBase members

        protected override void Dispose(bool dispoceManged)
        {
            if (m_Disposed)
                return;

            m_Disposed = true;
        }

        #endregion

        #region IOutputContract Implementation

        public void CalcOutputProperties()
        {
            double CaO = (from item in m_CurrentOutput.SlagComposition
                          where item.Element == "CaO"
                          select item.Percentage).First();

            double SiO2 = (from item in m_CurrentOutput.SlagComposition
                           where item.Element == "SiO2"
                           select item.Percentage).First();

            if (SiO2 != 0)
            {
                m_CurrentOutput.Basic1 = Math.Round(CaO / SiO2, 3);
            }


            double MgO = (from item in m_CurrentOutput.SlagComposition
                          where item.Element == "MgO"
                          select item.Percentage).First();

            if (SiO2 != 0)
            {
                m_CurrentOutput.Basic2 = Math.Round((CaO + MgO) / SiO2, 3);
            }

            double Al2O3 = (from item in m_CurrentOutput.SlagComposition
                            where item.Element == "Al2O3"
                            select item.Percentage).First();

            if (MgO != 0)
            {
                m_CurrentOutput.Basic3 = Math.Round(Al2O3 / MgO, 3);
            }

            CalcSlagChemicalParametrs();

            CalcMetallChemicalParametrs();

            double SInSlag = (from item in m_CurrentOutput.SlagComposition
                            where item.Element == "S"
                            select item.Percentage).First();

            double SInCastIron = (from item in m_CurrentOutput.CastIronComposition
                            where item.Element == "S"
                            select item.Percentage).First();

            m_CurrentOutput.LsActual = Math.Round(SInSlag/SInCastIron, 0);

            m_CurrentOutput.LsBalance = Math.Round(Math.Pow(10, 9.033*m_CurrentOutput.MetallZy+18.53*m_CurrentOutput.SlagRo-0.096*m_CurrentOutput.SlagDe-24.272), 0);

            m_CurrentOutput.LsRelatively = Math.Round((m_CurrentOutput.LsActual/m_CurrentOutput.LsBalance)*100, 0);

            m_CurrentOutput.ViscosityFor1450C = Math.Pow(10, 191.6149 - 562.4018 * m_CurrentOutput.SlagRo + 401.948 * Math.Pow(m_CurrentOutput.SlagRo, 2) + 6.74924 * (1000 / 1450));
            m_CurrentOutput.ViscosityFor1500C = Math.Pow(10, 191.6149 - 562.4018 * m_CurrentOutput.SlagRo + 401.948 * Math.Pow(m_CurrentOutput.SlagRo, 2) + 6.74924 * (1000 / 1500));
            m_CurrentOutput.ViscosityFor1550C = Math.Pow(10, 191.6149 - 562.4018 * m_CurrentOutput.SlagRo + 401.948 * Math.Pow(m_CurrentOutput.SlagRo, 2) + 6.74924 * (1000 / 1550));
            m_CurrentOutput.SurfaceTension1500С = 1032 + 133.674 * m_CurrentOutput.SlagDe - 196.86 * (1500 / 1000);
            m_CurrentOutput.Enthalpy = 4425.7 + 2095.9 * m_CurrentOutput.SlagDe + 421.67 * m_CurrentOutput.SlagDe * m_CurrentOutput.SlagDe;
            m_CurrentOutput.InitialMelting = 4491.389 * m_CurrentOutput.SlagRo - 1909;
            m_CurrentOutput.TemperatureOfCrystallization = 2629.24 * m_CurrentOutput.SlagRo - 518;
            m_CurrentOutput.SulfurAbsorbingCapacity = Math.Pow(10, (-9.8762 + 15.565 * m_CurrentOutput.SlagRo));

            //            {вязкость конечного шлака при 1450С}
 //Vsk1450KS:=POWER(10,(191.6149-562.4018*RoShlaka+401.948*RoShlaka*RoShlaka+6.74924*(1000/1450)));
 //{вязкость конечного шлака при 1500С}
 //Vsk1500KS:=POWER(10,(191.6149-562.4018*RoShlaka+401.948*RoShlaka*RoShlaka+6.74924*(1000/1500)));
 //{вязкость конечного шлака при 1550С}
 //Vsk1550KS:=POWER(10,(191.6149-562.4018*RoShlaka+401.948*RoShlaka*RoShlaka+6.74924*(1000/1550)));
 //{поверхностное натяжение конечного шлака при 1500С}
 //PN1500KS:=1032+133.674*deShlaka-196.86*(1500/1000);
 //{энтальпия конечного шлака}
 //EntKS:=4425.7+2095.9*deShlaka+421.67*deShlaka*deShlaka;
 //{температура начала плавления конечного шлака}
 //TNPKS:=4491.389*RoShlaka-1909;
 //{температура начала кристаллизации для конечного шлака}
 //TNKKS:=2629.24*RoShlaka-518;
 //{серопоглатительная способность конечного шлака}
 //CsKS:=POWER(10,(-9.8762+15.565*RoShlaka));



        }

        /// <summary>
        /// Calculation chemical parametrs of slag: de, ro
        /// </summary>
        private void CalcSlagChemicalParametrs()
        {
            List<Coupla> temp = new List<Coupla>();

            var SlagToSlagSystem = from item in m_CurrentOutput.SlagComposition
                                   select new { Element = item.Element, Percentage = item.Percentage };

            foreach (var item in SlagToSlagSystem)
            {
                Coupla tmp = Coupla.Create(item.Element, item.Percentage);
                temp.Add(tmp);
            }

            SlagSystem slagsystem = new SlagSystem(temp);
            slagsystem.CalcSlagSystemProperties();

            foreach (Coupla item in slagsystem.slagProperties)
            {
                if (item.Indicator == "Ro")
                {
                    m_CurrentOutput.SlagRo = Math.Round(item.Value, 3);
                }
                if (item.Indicator == "De")
                {
                    m_CurrentOutput.SlagDe = Math.Round(item.Value, 3);
                }
            }
        }

        /// <summary>
        /// Calculation chemical parametrs of metall: Zy, d
        /// </summary>
        private void CalcMetallChemicalParametrs()
        {
            List<Coupla> temp = new List<Coupla>();

            var CastIronToMetallSystem = from item in m_CurrentOutput.CastIronComposition
                                   select new { Element = item.Element, Percentage = item.Percentage };

            foreach (var item in CastIronToMetallSystem)
            {
                Coupla tmp = Coupla.Create(item.Element, item.Percentage);
                temp.Add(tmp);
            }

            MetallSystem metallsystem = new MetallSystem(temp);
            metallsystem.CalcMetallSystemProperties();

            foreach (Coupla item in metallsystem.metallProperties)
            {
                if (item.Indicator == "Zy")
                {
                    m_CurrentOutput.MetallZy = Math.Round(item.Value, 3);
                }
                if (item.Indicator == "d")
                {
                    m_CurrentOutput.Metalld = Math.Round(item.Value, 3);
                }
            }
        }

        public DataTable GetCastIron()
        {
            DataTable result = new DataTable();

            ///Columns
            result.Columns.Add(TableResources.NO_CAPTION, typeof(string));
            foreach (ChemicalСombination element in m_CurrentOutput.CastIronComposition)
            {
                result.Columns.Add(element.Element, typeof(double));
            }
            result.Columns.Add(TableResources.IRON_CAST_WEIGHT, typeof(string));

            ///Rows
            object[] chargeInRow = new object[result.Columns.Count];
            chargeInRow[0] = TableResources.COMPONENT_WEIGHT;
            for (int j = 0; j < m_CurrentOutput.CastIronComposition.Count; j++)
            {
                chargeInRow[j + 1] = Math.Round(m_CurrentOutput.CastIronComposition[j].Weight, Constants.NUMBER_ROUND);
            }
            chargeInRow[result.Columns.Count - 1] = Math.Round(m_CurrentOutput.CastIronWeight, Constants.NUMBER_ROUND);

            result.Rows.Add(chargeInRow);

            chargeInRow[0] = TableResources.PERCENTAGE;
            for (int j = 0; j < m_CurrentOutput.CastIronComposition.Count; j++)
            {
                chargeInRow[j + 1] = Math.Round(m_CurrentOutput.CastIronComposition[j].Percentage, Constants.NUMBER_ROUND);
            }
            chargeInRow[result.Columns.Count - 1] = 0;

            result.Rows.Add(chargeInRow);

            return result;
        }

        public DataTable GetSlag()
        {
            DataTable result = new DataTable();

            ///Columns
            result.Columns.Add(TableResources.NO_CAPTION, typeof(string));
            foreach (ChemicalСombination element in m_CurrentOutput.SlagComposition)
            {
                result.Columns.Add(element.Element, typeof(double));
            }
            result.Columns.Add(TableResources.SLAG_WEIGHT, typeof(string));

            ///Rows
            object[] chargeInRow = new object[result.Columns.Count];
            chargeInRow[0] = TableResources.COMPONENT_WEIGHT;
            for (int j = 0; j < m_CurrentOutput.SlagComposition.Count; j++)
            {
                chargeInRow[j + 1] = Math.Round(m_CurrentOutput.SlagComposition[j].Weight, Constants.NUMBER_ROUND);
            }
            chargeInRow[result.Columns.Count - 1] = Math.Round(m_CurrentOutput.SlagWeight, Constants.NUMBER_ROUND);

            result.Rows.Add(chargeInRow);

            chargeInRow[0] = TableResources.PERCENTAGE;
            for (int j = 0; j < m_CurrentOutput.SlagComposition.Count; j++)
            {
                chargeInRow[j + 1] = Math.Round(m_CurrentOutput.SlagComposition[j].Percentage, Constants.NUMBER_ROUND);
            }
            chargeInRow[result.Columns.Count - 1] = 0;

            result.Rows.Add(chargeInRow);

            return result;
        }

        public void GetOutput(Load load, Model model, ElementsDistribution distribution, Technology technology)
        {
            m_CurrentOutput = Output.Create();
            Output temp = CalculateOutput(load, model, distribution, technology);
            double KgTKS = temp.SlagWeight * 1000 / (double)temp.CastIronWeight;
            model.Qs = KgTKS / (double)1000;

            m_CurrentOutput = CalculateOutput(load, model, distribution, technology);
        }

        private Output CalculateOutput(Load load, Model model, ElementsDistribution distribution, Technology technology)
        {
            Output result = Output.Create();
            double allSlag = 0, allIronCast = 0;
            ILoadContract m_LoadController = new LoadController(null);
            IModelContract m_ModelController = new ModelController(null);
            m_ModelController.CurrentModel = model;
            m_LoadController.CurrentLoad = load;
            List<string> allChemicalCombinations = m_LoadController.GetAllChemicalСombinationsInAllCharges();

            foreach (string item in allChemicalCombinations)
            {
                double K = 0, L = 0;
                ElementDistribution parts = (from part in distribution.ElementsDistributionList
                                             where part.Title.Equals(item)
                                             select part).FirstOrDefault<ElementDistribution>();

                if (parts != null && parts.Kind.Equals("Portion"))
                {
                    ElementModel rule = (from ruleItem in model.ElementsModelList
                                         where ruleItem.Title.Equals(item)
                                         select ruleItem).FirstOrDefault<ElementModel>();

                    //ChemicalСombination curElem=from 
                    if (rule != null)
                    {
                        K = m_ModelController.GetElementDistribution(rule, load, technology);
                        L = (model.Qs * K * rule.DistributionConstant) / (1 + (model.Qs * K * rule.DistributionConstant));
                        ///?????????///
                        result.CastIronComposition.Add(new ChemicalСombination(parts.LookInCastIron, 0) { Weight = (m_LoadController.CurrentLoad.TotalLoadChargeChemicalElements.Where(el => el.Element.Equals(item)).First<ChemicalСombination>().Weight) * (1 - L) * rule.CastIronConstant });
                        allIronCast += result.CastIronComposition[result.CastIronComposition.Count - 1].Weight;
                        result.SlagComposition.Add(new ChemicalСombination(parts.LookInSlag, 0) { Weight = (m_LoadController.CurrentLoad.TotalLoadChargeChemicalElements.Where(el => el.Element.Equals(item)).First<ChemicalСombination>().Weight) * L * rule.SlagConstant });
                        allSlag += result.SlagComposition[result.SlagComposition.Count - 1].Weight;
                        //////
                        result.LElemnets.Add(Coupla.Create("L" + parts.LookInCastIron, result.CastIronComposition[result.CastIronComposition.Count - 1].Weight));
                    }

                }

                if (parts != null && parts.Kind.Equals("Slag"))
                {
                    result.SlagComposition.Add(new ChemicalСombination(parts.LookInSlag, 0) { Weight = m_LoadController.CurrentLoad.TotalLoadChargeChemicalElements.Where(el => el.Element.Equals(item)).First<ChemicalСombination>().Weight });
                    allSlag += result.SlagComposition[result.SlagComposition.Count - 1].Weight;
                }

                if (parts != null && parts.Kind.Equals("IronCast"))
                {
                    result.CastIronComposition.Add(new ChemicalСombination(parts.LookInCastIron, 0) { Weight = m_LoadController.CurrentLoad.TotalLoadChargeChemicalElements.Where(el => el.Element.Equals(item)).First<ChemicalСombination>().Weight });
                    allIronCast += result.CastIronComposition[result.CastIronComposition.Count - 1].Weight;
                }
            }

            result.CastIronComposition.Add(new ChemicalСombination("C", model.Carbon));
            result.CastIronComposition.Add(new ChemicalСombination("P", model.Phosphorus));

            result.CastIronWeight = allIronCast;
            result.SlagWeight = allSlag;

            foreach (ChemicalСombination item in result.SlagComposition)
            {
                item.Percentage = item.Weight * 100 / (double)result.SlagWeight;
            }

            foreach (ChemicalСombination item in result.CastIronComposition)
            {
                item.Percentage = item.Weight * (100 - model.Phosphorus - model.Carbon) / (double)result.CastIronWeight;
            }

            return result;
        }

        #endregion

        #region Fields

        private bool m_Disposed = false;
        private Output m_CurrentOutput = null;

        #endregion

    }
}
